/*
 *  Copyright (C) 2025 ameise <ameise.wang@gmail.com> - All Rights Reserved
 *
 *  This file is part of e3net.
 *
 *  e3net is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  e3net is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with e3net. If not, see <https://www.gnu.org/licenses/>.
 */

package packet

import (
	"encoding/binary"
	"unsafe"
)

const HeadSize = 8
const (
	cryptoBit   byte = 1 << 0 //bool
	compressBit byte = 1 << 1 //bool
	bigPacket   byte = 1 << 2 //bool
)

func newHead() *head {
	return &head{
		Mark: &[HeadSize]byte{},
	}
}

func newHeadWarp(b []byte) *head {
	return &head{
		Mark: (*[HeadSize]byte)(unsafe.Pointer(unsafe.SliceData(b))),
	}
}

type head struct {
	Mark *[HeadSize]byte
}

func (ts *head) init() {
	for i := 0; i < HeadSize; i++ {
		ts.Mark[i] = 0
	}
}

func (ts *head) toBytes() []byte {
	return ts.Mark[:]
}

func (ts *head) fromBytes(b []byte) {
	copy(ts.Mark[:], b)
}

func (ts *head) warp(b []byte) {
	ts.Mark = (*[HeadSize]byte)(unsafe.Pointer(unsafe.SliceData(b)))
}

// getID 消息包ID
func (ts *head) getID() uint32 {
	return binary.BigEndian.Uint32(ts.Mark[0:4])
}

// setId 设置消息包 ID
func (ts *head) setId(id uint32) {
	binary.BigEndian.PutUint32(ts.Mark[0:4], id)
}

// isCompress 消息包是否压缩
func (ts *head) isCompress() bool {
	return ts.Mark[4]&compressBit != 0
}

// setCompress 设置压缩
func (ts *head) setCompress(do bool) {
	ts.Mark[4] &= ^compressBit
	if do {
		ts.Mark[4] |= compressBit
	}
}

// isCrypto 消息包是否加密
func (ts *head) isCrypto() bool {
	return ts.Mark[4]&cryptoBit != 0
}

// setCrypto 设置加密
func (ts *head) setCrypto(do bool) {
	ts.Mark[4] &= ^cryptoBit
	if do {
		ts.Mark[4] |= cryptoBit
	}
}

// bodySize 消息包长度
func (ts *head) bodySize() uint16 {
	return binary.BigEndian.Uint16(ts.Mark[6:8])
}

func (ts *head) setBodySize(size uint16) {
	binary.BigEndian.PutUint16(ts.Mark[6:8], size)
}
